package lucene.server.client;

import lucene.server.client.enums.*;
import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

public class ClientWrapper {
    // 要操作的索引名
    private String name;
    // 对索引的操作类型
    private QueryType type;
    //分页信息
    private Integer page=1;
    private Integer pageSize=10;
    private Map<String,Boolean> orders = new LinkedHashMap<>();
    // 当前操作的连接类型
    private LinkType currentLink;
    // 当前正在构建的段
    private QueryNode currentSection;
    // 操作相关的字段
    private String field = "*";
    // 查询条件集合
    private List<QueryNode> nodes = new ArrayList<>();

    public ClientWrapper(){ }
    public ClientWrapper(String name){
        this.name = name;
    }
    public static ClientWrapper create() {
        return new ClientWrapper();
    }
    public static ClientWrapper create(String indexName) {
        return new ClientWrapper(indexName);
    }

    /**
     * 设置查询的来源表名。
     *
     * @param indexName 服务器上的索引名称。
     * @return 当前QueryBuilder对象，以支持链式调用。
     */
    public ClientWrapper From(String indexName){
        this.name = indexName;
        return  this;
    }
    /**
     * 构建一个SELECT查询。
     *
     * @param field 可变参数，表示一个或多个字段名，这些字段的数据将在查询中被选择。
     * @return 当前QueryBuilder对象，允许进行链式调用以构建更复杂的查询。
     */
    public ClientWrapper SELECT(String field) {
        this.type = QueryType.SELECT;
        this.field = field;
        return this;
    }

    public ClientWrapper COUNT() {
        this.type = QueryType.COUNT;
        return this;
    }

    /**
     * 开始构建一个UPDATE查询。
     *
     * @return 当前QueryBuilder对象，以便进行后续的链式调用。
     */
    public ClientWrapper UPDATE() {

        this.type = QueryType.UPDATE;
        return this;
    }
    /**
     * 开始构建一个DELETE查询。
     * 注意：此处可能存在错误，因为DELETE查询应设置QueryType为DELETE而不是INSERT。
     *
     * @return 当前QueryBuilder对象，以便进行后续的链式调用。
     */
    public ClientWrapper DELETE() {
        this.type = QueryType.DELETE;
        return this;
    }
    /**
     * 开始构建一个GROUP BY查询部分。
     *
     * @return 当前QueryBuilder对象，以便进行后续的链式调用。
     */
    public ClientWrapper GROUP(String field) {

        this.field = field;
        this.type = QueryType.GROUP;
        return this;
    }
    /**
     * 开始构建一个INSERT查询。
     *
     * @return 当前QueryBuilder对象，以便进行后续的链式调用。
     */
    public ClientWrapper INSERT() {
        this.type = QueryType.INSERT;
        return this;
    }
    /**
     * 设置查询的分页信息。
     *
     * @param page     页码，从1开始。
     * @param pageSize 每页的记录数。
     *
     * @return 当前的QueryBuilder对象，以便进行后续的链式调用。
     */
    public ClientWrapper Page(int page, int pageSize) {
        this.page = page;
        this.pageSize = pageSize;
        return this;
    }
    /**
     * 设置下一个条件的逻辑与操作，默认可以不使用。
     *
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper and() {
        this.currentLink = LinkType.AND;
        return this;
    }
    /**
     * 设置下一个条件的逻辑或操作。
     *
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper or() {
        this.currentLink = LinkType.OR;
        return this;
    }
    /**
     * 开始一个新的查询段,相当于前括号 "("。
     *
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper sectionBegin() {
        //只能实现一次嵌套
        if(this.currentSection != null) {
            return this;
        }
        this.currentSection = new QueryNode();
        this.currentSection.setOperator(Operator.SECTION);
        this.currentSection.setLink(getLastLinkType());
        return this;
    }
    /**
     * 结束当前查询段,相当于后括号 ")"，并将其添加到查询节点列表中。
     *
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper sectionEnd() {
        if(this.currentSection == null) {
            return this;
        }
        QueryNode sectionNode =deepCopy(this.currentSection);
        this.nodes.add(sectionNode);
        this.currentSection = null;
        return this;
    }
    /**
     * 添加等于（EQ）条件。
     *
     * @param field 字段名
     * @param value 字段值
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper eq(String field, Object value) {
        if (isNullOrEmpty(field) || isNullOrEmpty(value)){ return this;}
        this.addNode(new QueryNode(field, Operator.EQ, getLastLinkType(), value ));
        return this;
    }
    /**
     * 添加不等于（NE）条件。
     * 注意 NE条件 由于LUCENE底层原因，不能只有一个NE条件
     * 具体查看：https://lucene.apache.org/core/8_11_3/core/org/apache/lucene/search/BooleanClause.Occur.html#MUST_NOT
     * public static final BooleanClause.Occur MUST_NOT
     * Use this operator for clauses that must not appear in the matching documents.
     * Note that it is not possible to search for queries that only consist of a clause.
     * These clauses do not contribute to the score of documents.MUST_NOT
     * @param field 字段名
     * @param value 字段值
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper ne(String field, Object value) {
        if (isNullOrEmpty(field) || isNullOrEmpty(value)){ return this;}
        this.addNode(new QueryNode(field, Operator.NE, getLastLinkType(), value ));
        return this;
    }
    /**
     * 添加大于（GT）条件。
     *
     * @param field 字段名
     * @param value 字段值
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper gt(String field, Object value) {
        if (isNullOrEmpty(field) || isNullOrEmpty(value)){ return this;}
        this.addNode(new QueryNode(field, Operator.GT, getLastLinkType(), value ));
        return this;
    }
    /**
     * 添加小于（LT）条件。
     *
     * @param field 字段名
     * @param value 字段值
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper lt(String field, Object value) {
        if (isNullOrEmpty(field) || isNullOrEmpty(value)){ return this;}
        this.addNode(new QueryNode(field, Operator.LT, getLastLinkType(), value ));
        return this;
    }
    /**
     * 添加大于等于（GE）条件。
     *
     * @param field 字段名
     * @param value 字段值
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper ge(String field, Object value) {
        if (isNullOrEmpty(field) || isNullOrEmpty(value)){ return this;}
        this.addNode(new QueryNode(field, Operator.GE, getLastLinkType(), value ));
        return this;
    }
    /**
     * 添加小于等于（LE）条件。
     *
     * @param field 字段名
     * @param value 字段值
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper le(String field, Object value) {
        if (isNullOrEmpty(field) || isNullOrEmpty(value)){ return this;}

        this.addNode(new QueryNode(field, Operator.LE, getLastLinkType(), value ));
        return this;
    }
    /**
     * 添加介于（BETWEEN）条件。
     *
     * @param field 字段名
     * @param lowValue 区间下限
     * @param upValue 区间上限
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper between(String field, Object lowValue, Object upValue) {
        if (isNullOrEmpty(field) || isNullOrEmpty(lowValue) || isNullOrEmpty(upValue)){ return this;}
        QueryNode node = new QueryNode(field, Operator.BETWEEN, getLastLinkType(), lowValue );
        node.getValues().add(String.valueOf(upValue));
        this.addNode(node);
        return this;
    }
    /**
     * 添加在（IN）列表中的条件。
     *
     * @param field 字段名
     * @param values 值列表
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper in(String field, List<Object> values) {
        if (isNullOrEmpty(field) || isNullOrEmpty(values)){ return this;}
        this.addNode(new QueryNode(field, Operator.IN, getLastLinkType(), values ));
        return this;
    }
    /**
     * 添加类似（LIKE）条件。
     *
     * @param field 字段名
     * @param value 模式值
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper like(String field , Object value) {
        if (isNullOrEmpty(field) || isNullOrEmpty(value)){ return this;}
        this.addNode(new QueryNode(field, Operator.LIKE, getLastLinkType(), value ));
        return this;
    }
    /**
     * 添加为空（IS NULL）条件。
     *
     * @param field 字段名
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper isNull(String field) {
        this.addNode(new QueryNode(field, Operator.ISNULL, getLastLinkType(), null ));
        return this;
    }
    /**
     * 添加不为空（IS NOT NULL）条件。
     *
     * @param field 字段名
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper isNotNull(String field) {
        this.addNode(new QueryNode(field, Operator.ISNOTNULL, getLastLinkType(), null ));
        return this;
    }
    /**
     * 添加不在（NOT IN）列表中的条件。
     *
     * @param field 字段名
     * @param values 值列表
     * @return 当前QueryWrapper实例，支持链式操作。
     */
    public ClientWrapper notIn(String field, List<Object> values) {

        if (isNullOrEmpty(field) || isNullOrEmpty(values)){ return this;}

        this.addNode(new QueryNode(field, Operator.ISNOTNULL, getLastLinkType(), values ));
        return this;
    }
    public ClientWrapper orderBy(String orderField, boolean isDesc) {

       this.orders.put(orderField,isDesc);

        return this;
    }
    /**
     * 将查询节点添加到列表中，根据当前是否在段中，决定是否设置连接类型。
     *
     * @param node 待添加的查询节点
     */
    public void  addNode(QueryNode node) {
        if (this.currentSection != null){
            node.setLink(getLastLinkType());
            this.currentSection.children.add(node);
        }else{
            this.nodes.add(node);
        }
    }

    /**
     * 获取当前操作的连接类型，并重置为null。
     *
     * @return 当前操作的连接类型
     */
    private LinkType getLastLinkType() {
        if (LinkType.OR.equals(this.currentLink)){
            this.currentLink = null;
            return LinkType.OR;
        } else if (LinkType.NOT.equals(this.currentLink)) {
            this.currentLink = null;
            return LinkType.NOT;
        }else{

            this.currentLink = null;
            return LinkType.AND;
        }
    }
    public QueryNode deepCopy(QueryNode source) {
        QueryNode node = new QueryNode();
        node.setField(source.field);
        node.setOperator(source.operator);
        node.setLink(source.link);
        source.values.forEach(value -> node.values.add(value));
        node.setValues(new ArrayList<>(source.values));
        for (QueryNode sourceChild : source.getChildren()){
            QueryNode childNode = new QueryNode();
            childNode.setField(sourceChild.field);
            childNode.setOperator(sourceChild.operator);
            childNode.setLink(sourceChild.link);
            sourceChild.values.forEach(value -> childNode.values.add(value));
            node.getChildren().add(childNode);
        }
        return node;
    }
    public String toString() {
        return  build();
    }

    /**
     * 查询节点类，用于构建查询条件树。
     * 实现Serializable接口，以便于对象的序列化和反序列化。
     */
    class QueryNode implements Serializable {

        /**
         * 查询节点的值列表。
         */
        private List<String> values = new ArrayList<>();
        /**
         * 查询字段。
         */
        private String field;
        /**
         * 查询操作符，用于定义查询条件的比较方式。
         */
        private Operator operator;
        /**
         * 查询连接类型，用于定义多个查询条件之间的逻辑关系。
         */
        private LinkType link;
        /**
         * 子查询节点列表，用于构建查询条件树的子节点。
         */
        private List<QueryNode> children = new ArrayList<>();


        public QueryNode(){}
        public QueryNode(String field, Operator operator, LinkType link, Object value) {
            this.field = field;
            this.operator = operator;
            this.link = link;
            if (value instanceof List) {
                List<String> listValue = (List<String>) value;
                this.values.addAll(listValue);
            } else {
                this.values.add(String.valueOf(value));
            }
        }

        public List<QueryNode> getChildren() {
            return this.children;
        }

        public void setChildren(List<QueryNode> children) {
            this.children = children;
        }

        public LinkType getLink() {
            return this.link;
        }

        public void setLink(LinkType link) {
            this.link = link;
        }

        public Operator getOperator() {
            return this.operator;
        }

        public void setOperator(Operator operator) {
            this.operator = operator;
        }
        public String getField() {
            return this.field;
        }
        public void setField(String field) {
            this.field = field;
        }
        public List<String> getValues() {
            return this.values;
        }
        public void setValues(List<String> values) {
            this.values.addAll(values);
        }
    }
    //判断对象为null 或者为空
    private boolean isNullOrEmpty(Object obj) {
        if (obj == null) {
            return true;
        } else if (obj instanceof String) {
            return ((String) obj).isEmpty();
        } else if (obj instanceof Collection) {
            return ((Collection<?>) obj).isEmpty();
        } else if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        } else if (obj instanceof Optional) {
            return !((Optional<?>) obj).isPresent();
        } else if (obj.getClass().isArray()) {
            return java.lang.reflect.Array.getLength(obj) == 0;
        }
        // 如果不匹配上述任何类型，则认为非空
        return false;
    }
    public String build(){
        StringBuilder sb = new StringBuilder("{");
        if (!isNullOrEmpty(this.name)){
            sb.append("\"name\":\"").append(this.name).append("\",");
        }
        if (!isNullOrEmpty(this.type)){
            sb.append("\"type\":\"").append(this.type.toString()).append("\",");
        }
        if (!isNullOrEmpty(this.field)){
            sb.append("\"field\":\"").append(this.field).append("\",");
        }
        if (!isNullOrEmpty(this.page)){
            sb.append("\"page\":").append(this.page).append(",");
        }
        if (!isNullOrEmpty(this.pageSize)){
            sb.append("\"pageSize\":").append(this.pageSize).append(",");
        }
        if(orders.size()>0){
            sb.append("\"orders\":").append("[");
            Iterator<Map.Entry<String, Boolean>> entries = orders.entrySet().iterator();
            while(entries.hasNext()){
                Map.Entry<String, Boolean> entry = entries.next();
                sb.append("{\""+entry.getKey()+"\":").append(entry.getValue().toString() +"}");
                if (entries.hasNext()) {
                    sb.append(",");
                }
            }
            sb.append("],");
        }
        sb.append("\"nodes\":").append("[");
        Iterator<QueryNode> iterator = nodes.iterator();
        while (iterator.hasNext()) {
            QueryNode current = iterator.next();
            sb.append(buildNodeJson(current));
            if (iterator.hasNext()) {
                sb.append(",");
            }
        }
        sb.append("]}");
        return sb.toString();
    }
    private String buildNodeJson(QueryNode node){
        StringBuilder sb = new StringBuilder("{");

        sb.append("\"values\":").append("[");
            sb.append(node.values.stream()
                    .map(value -> "\"" + value + "\"")
                    .collect(Collectors.joining(",")));
        sb.append("],");

        if (!isNullOrEmpty(node.field)){
            sb.append("\"field\":\"").append(node.field).append("\",");
        }
        if (!isNullOrEmpty(node.operator)){
            sb.append("\"operator\":\"").append(node.operator.toString()).append("\",");
        }
        if (!isNullOrEmpty(node.link)){
            sb.append("\"link\":\"").append(node.link.toString()).append("\",");
        }
        sb.append("\"children\":").append("[");

        Iterator<QueryNode> iterator = node.children.iterator();
        while (iterator.hasNext()) {
            QueryNode current = iterator.next();
            sb.append(buildNodeJson(current));
            if (iterator.hasNext()) {
                sb.append(",");
            }
        }
        sb.append("]");
        sb.append("}");
        return sb.toString();
    }
}
